package com.easydisk.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easydisk.constant.CommonConstant;
import com.easydisk.constant.FileConstant;
import com.easydisk.file.mapper.UploadFileMapper;
import com.easydisk.file.mapper.UserFileMapper;
import com.easydisk.file.model.entity.UploadFile;
import com.easydisk.file.model.entity.UserFile;
import com.easydisk.file.model.vo.BreadcrumbVO;
import com.easydisk.file.model.vo.FolderTreeVO;
import com.easydisk.file.model.vo.UserFileSearchVO;
import com.easydisk.file.model.vo.UserFileVO;
import com.easydisk.file.service.ShareService;
import com.easydisk.file.service.UploadFileService;
import com.easydisk.file.service.UserFileService;
import com.easydisk.response.ResponseCode;
import com.easydisk.common.util.FileUtil;
import com.easydisk.common.util.HttpUtil;
import com.easydisk.common.util.IdGenerator;
import com.easydisk.common.util.StringListUtil;
import com.easydisk.common.util.file.type.context.FileTypeContext;
import com.easydisk.vo.UserFileParam;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户文件信息表 服务实现类
 *
 * @author word
 * @since 2023-09-08
 */
@Slf4j
@Service
public class UserFileServiceImpl extends ServiceImpl<UserFileMapper, UserFile>
        implements UserFileService {

    @Autowired
    private UserFileMapper userFileMapper;

    @Autowired
    private ShareService shareService;


    @Autowired
    private UploadFileMapper uploadFileMapper;

    @Autowired
    private UploadFileService uploadFileService;


    /**
     * 获取parentId下的没有逻辑删除的文件列表
     */
    @Override
    public List<UserFileVO> getUserFileList(Long parentId, String fileTypes, Long userId) {

        return getUserFileList(parentId, fileTypes, userId, FileConstant.DelFlagEnum.NO.getCode());

    }

    /**
     * 获取parentId(不包括parentId)下的文件列表
     */
    @Override
    public List<UserFileVO> getUserFileList(Long parentId, String fileTypes, Long userId, Integer delFlag) {
        List<Integer> fileTypeArray = null;
        // 文件父Id等于0,直接返回
        if (Objects.equals(CommonConstant.ZERO_LONG, parentId)) {
            return Lists.newArrayList();
        }
        // 构建需要获取的文件类型(默认全部文件类型)
        if (!Objects.equals(fileTypes, FileConstant.ALL_FILE_TYPE)) {
            fileTypeArray = StringListUtil.string2IntegerList(fileTypes);
        }
        return userFileMapper
                .selectUserFileVOListByUserIdAndFileTypeAndParentIdAndDelFlag
                        (userId, fileTypeArray, parentId, delFlag);
    }

    /**
     * 创建文件夹
     */
    @Override
    public void addFolder(Long parentId, String folderName, Long userId) {

        addUserFile(parentId, folderName, FileConstant.FolderFlagEnum.YES,
                null, null, userId, null);

    }

    /**
     * 保存用户文件信息
     *
     */
    @Override
    public void addUserFile(Long parentId, String filename,
                            FileConstant.FolderFlagEnum isFolder, Integer fileType,
                            Long realFileId, Long userId, String fileSizeDesc) {
        // 装配成userFile对象
        UserFile userFile = convertToUserFile(parentId, userId, filename,
                isFolder, fileType, realFileId, fileSizeDesc);
        int insert = userFileMapper.insert(userFile);
        if (insert != CommonConstant.ONE_INT) {
            throw new RuntimeException("保存文件信息失败");
        }
    }

    /**
     * 拼装用户文件实体信息
     */
    private UserFile convertToUserFile(Long parentId, Long userId, String filename,
                                       FileConstant.FolderFlagEnum folderFlag, Integer fileType,
                                       Long realFileId, String fileSizeDesc) {
        UserFile userFile = new UserFile();
        userFile.setUserId(userId);
        userFile.setParentId(parentId);
        userFile.setId(IdGenerator.nextId());
        userFile.setFilename(filename);
        userFile.setFileType(fileType);
        userFile.setFolderFlag(folderFlag.getCode());
        userFile.setFileSizeDesc(fileSizeDesc);
        userFile.setRealFileId(realFileId);
        userFile.setCreateUser(userId);
        userFile.setCreateTime(new Date());
        userFile.setUpdateUser(userId);
        userFile.setUpdateTime(new Date());
        userFile.setDelFlag(FileConstant.DelFlagEnum.NO.getCode());
        handleDuplicateFileName(userFile);
        return userFile;
    }

    /**
     * 处理重复文件名
     * 比如 "新建文件夹(1)" 修改为 "新建文件夹(2)"
     *
     */
    private void handleDuplicateFileName(UserFile userFile) {
        String newFileName = userFile.getFilename();
        // 文件夹或者文件的名字,没有.doc, .pdf
        String  name;
        // 文件夹或者文件的后缀，比如 文件：.doc, 文件夹： ""
        String  suffix;
        int position = newFileName.lastIndexOf(CommonConstant.POINT_STR);
        if (position == CommonConstant.MINUS_ONE_INT) {
            name = newFileName;
            suffix = CommonConstant.EMPTY_STR;
        } else {
            name = newFileName.substring(CommonConstant.ZERO_INT, position);
            suffix = FileUtil.getFileSuffix(newFileName);
        }
        List<UserFileVO> fileVOList = userFileMapper
                .selectUserFileVOListByUserIdAndFileTypeAndParentIdAndDelFlag
                        (userFile.getUserId(), null, userFile.getParentId(),
                                FileConstant.DelFlagEnum.NO.getCode());
        // 是否有重名的文件或者文件夹，全都不满足才会返回true
        boolean isDuplicateFileName = fileVOList.stream()
                .noneMatch(fileVO -> userFile.getFilename()
                        .equals(fileVO.getFilename()));
        if (isDuplicateFileName) {
            return;
        }
        // 统计有多少文件名称相同的文件或者文件夹
        List<String> duplicateFileNameList = fileVOList.stream()
                .map(UserFileVO::getFilename)
                .filter(fileName -> fileName.startsWith(name))
                .filter(fileName -> {
                    int pointPosition = fileName.lastIndexOf(CommonConstant.POINT_STR);
                    String fileNameSuffix = CommonConstant.EMPTY_STR;
                    if (pointPosition != CommonConstant.MINUS_ONE_INT) {
                        fileNameSuffix = FileUtil.getFileSuffix(fileName);
                    }
                    return Objects.equals(suffix, fileNameSuffix);
                })
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(duplicateFileNameList)) {
            return;
        }
        // 重命名
        newFileName = name +
                // 左括号 (
                FileConstant.CN_LEFT_PARENTHESES_STR +
                (duplicateFileNameList.size()) +
                // 右括号 )
                FileConstant.CN_RIGHT_PARENTHESES_STR +
                suffix;
        userFile.setFilename(newFileName);
    }


    /**
     * 文件重命名
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateFilename(Long fileId, String newFilename, Long userId) {
        UserFile exit = this.getUserFileByIdAndUserId(fileId, userId);
        if (Objects.equals(exit.getFilename(), newFilename)) {
            throw new RuntimeException("请使用一个新名称吧");
        }
        // 同目录下是否有重复名称的文件
        long cnt = this.getDuplicateFileNameInDirCount(userId, newFilename, exit.getParentId());
        if (cnt > CommonConstant.ZERO_INT) {
            throw new RuntimeException("名称已被占用");
        }
        exit.setFilename(newFilename);
        exit.setUpdateUser(userId);
        exit.setUpdateTime(new Date());
        if (userFileMapper.updateById(exit) != CommonConstant.ONE_INT) {
            throw new RuntimeException("文件重命名失败");
        }
    }

    /**
     * 根据用户id和文件id查询对应的文件信息
     *
     */
    @Override
    public UserFile getUserFileByIdAndUserId(Long fileId, Long userId) {
        UserFile userFile = userFileMapper.selectById(fileId);
        if (Objects.isNull(userFile)) {
            throw new RuntimeException("该用户没有此文件");
        }
        if (!Objects.equals(userFile.getUserId(), userId)) {
            throw new RuntimeException("该用户没有此文件");
        }
        if (Objects.equals(FileConstant.DelFlagEnum.YES.getCode(), userFile.getDelFlag())) {
            throw new RuntimeException("该用户没有此文件");
        }
        return userFile;
    }


    /**
     * 删除文件(批量)
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds( List<Long> fileIdList, Long userId) {
        // 转换为id列表
        // 批量删除idr
        if (CollectionUtils.isNotEmpty(fileIdList)) {
            for (Long id : fileIdList) {
                UpdateWrapper<UserFile> queryWrapper = new UpdateWrapper<>();
                queryWrapper.eq("id", id);
                queryWrapper.eq("user_id", userId);
                queryWrapper.set("del_flag", FileConstant.DelFlagEnum.YES.getCode());
                queryWrapper.set("update_user", userId);
                queryWrapper.set("update_time", new Date());
                userFileMapper.update(null, queryWrapper);
            }
        }
        //  更新用户分享的状态
        String allAvailableFileIdByFileIds = getAllAvailableFileIdByFileIds(StringListUtil.longListToString(fileIdList));
        List<Long> longList = StringListUtil.string2LongList(allAvailableFileIdByFileIds);
        shareService.refreshShareStatus(longList);

    }

    /**
     * 通过文件id集合获取所有可用的文件id和子文件id
     *
     */
    @Override
    public String getAllAvailableFileIdByFileIds(String fileIds) {
        List<Long> fileIdList = StringListUtil.string2LongList(fileIds);
        List<Long> allAvailableFileId = Lists.newArrayList(fileIdList);
        fileIdList.forEach(fileId -> findAllAvailableFileIdByFileId(allAvailableFileId, fileId));
        return StringListUtil.longListToString(allAvailableFileId);
    }

    /**
     * 校验所有的父文件夹以及当前文件有效
     *
     */
    @Override
    public boolean checkAllUpFileAvailable(List<Long> fileIds) {
        for (Long fileId : fileIds) {
            if (!checkUpFileAvailable(fileId)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 校验当前文件和所有父文件夹是否均正常
     *
     */
    private boolean checkUpFileAvailable(Long fileId) {
        UserFile userFile = userFileMapper.selectById(fileId);
        if (userFile.getDelFlag().equals(FileConstant.DelFlagEnum.YES.getCode())) {
            return false;
        }
        if (userFile.getParentId().equals(CommonConstant.ZERO_LONG)) {
            return true;
        }
        return checkUpFileAvailable(userFile.getParentId());
    }

    /**
     * 递归查询所有有效的子节点id
     *
     */
    private void findAllAvailableFileIdByFileId(List<Long> allAvailableFileId, Long fileId) {
        if (!isFolder(fileId)) {
            return;
        }
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("parent_id", fileId);
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        query.select("id");

        List<UserFile> childrenFileIds = userFileMapper.selectList(query);

        if (CollectionUtils.isEmpty(childrenFileIds)) {
            return;
        }
        for (UserFile  userFile : childrenFileIds) {
            allAvailableFileId.add(userFile.getId());
        }
        childrenFileIds.forEach(childrenFile ->
                findAllAvailableFileIdByFileId(allAvailableFileId, childrenFile.getId()));
    }

    /**
     * 校验是不是文件夹
     */
    @Override
    public boolean isFolder(Long fileId) {
        UserFile userFile = userFileMapper.selectById(fileId);
        return isFolder(userFile);
    }

    /**
     * 校验是不是文件夹
     */
    @Override
    public boolean isFolder(UserFile userFile) {
        if (userFile == null) {
            throw new RuntimeException("文件或者文件夹不存在");
        }
        return Objects.equals(FileConstant.FolderFlagEnum.YES.getCode(), userFile.getFolderFlag());
    }

    /**
     * 校验是不是文件夹
     * @param @UserFileVO 文件返回vo
     */
    private boolean isFolder(UserFileVO userFileVO) {
        if (userFileVO == null) {
            throw new RuntimeException("文件或者文件夹不存在");
        }
        return Objects.equals(FileConstant.FolderFlagEnum.YES.getCode(), userFileVO.getFolderFlag());
    }

    /**
     * 获取文件夹树
     *
     */
    @Override
    public List<FolderTreeVO> getFolderTree(Long userId) {
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("user_id", userId);
        query.eq("parent_id", CommonConstant.ZERO_LONG);
        UserFile userFile = userFileMapper.selectOne(query);
        return assembleFolderTree(userFile);
    }



    /**
     * 拼装文件夹树(获取文件夹的父节点是0的子文件夹)
     *
     */
    private List<FolderTreeVO> assembleFolderTree(UserFile userFile) {
        if (userFile == null) {
            return new ArrayList<>();
        }
        FolderTreeVO folderTreeVO = FolderTreeVO.assembleFolderTreeNode(userFile);
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("parent_id", userFile.getId());
        query.eq("folder_flag", FileConstant.FolderFlagEnum.YES.getCode());
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        List<UserFile> userFileList = userFileMapper.selectList(query);
        List<FolderTreeVO> folderTreeVOList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(userFileList)) {
            for (UserFile childrenUserFile : userFileList) {
                List<FolderTreeVO> folderTreeVOS = assembleFolderTree(childrenUserFile);
                folderTreeVO.getChildren().addAll(folderTreeVOS);
            }
        }
        folderTreeVOList.add(folderTreeVO);
        return folderTreeVOList;
    }

    /**
     * 查询文件详情，已父类为开始
     */
    @Override
    public UserFileVO getUserFileInfo(Long fileId, Long userId) {
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("parent_id", fileId);
        query.eq("user_id", userId);
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        UserFile userFile = userFileMapper.selectOne(query);
        UserFileVO userFileVO = new UserFileVO();
        BeanUtils.copyProperties(userFile, userFileVO);
        userFileVO.setFileId(userFile.getId());
        return userFileVO;
    }


    /**
     * 查询文件详情
     */
    @Override
    public UserFileVO getNotParentUserFileInfo(Long fileId, Long userId) {
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("id", fileId);
        query.eq("user_id", userId);
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        UserFile userFile = userFileMapper.selectOne(query);
        UserFileVO userFileVO = new UserFileVO();
        BeanUtils.copyProperties(userFile, userFileVO);
        userFileVO.setFileId(userFile.getId());
        return userFileVO;
    }


    /**
     * 通过文件名搜索文件
     */
    @Override
    public List<UserFileSearchVO> search(String keyword, String fileTypes, Long userId) {
        List<Integer> fileTypeArray = null;
        if (!Objects.equals(fileTypes, FileConstant.ALL_FILE_TYPE)) {
            fileTypeArray = StringListUtil.string2IntegerList(fileTypes);
        }
        List<UserFileSearchVO> userFileSearchVOList = userFileMapper
                .selectUserFileVOListByUserIdAndFilenameAndFileTypes(userId, keyword, fileTypeArray);
        // 获取userFileSearchVOList每个元素的父节点名称
        if (CollectionUtils.isNotEmpty(userFileSearchVOList)) {
            QueryWrapper<UserFile> queryWrapper = new QueryWrapper<>();
            List<Long> parentIdList = userFileSearchVOList.stream()
                    .map(UserFileSearchVO::getParentId).collect(Collectors.toList());
            queryWrapper.in("\"id\"", parentIdList);
            queryWrapper.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
            queryWrapper.select("\"id\"", "filename");
            List<UserFile> userFileList = userFileMapper.selectList(queryWrapper);
            final Map<Long, String> filePositionMap = userFileList.stream()
                    .collect(Collectors.toMap(UserFile::getId, UserFile::getFilename));
            userFileSearchVOList.forEach(userFileSearchVO ->
                    userFileSearchVO.setParentFilename(filePositionMap.get(userFileSearchVO.getParentId())));
        }
        return userFileSearchVOList;
    }


    /**
     * 批量复制文件
     */
    @Override
    public void copyFiles(String fileIds, Long targetParentId, Long userId) {
        if (!isFolder(targetParentId, userId)) {
            throw new RuntimeException("请选择要复制到的文件夹");
        }
        if (!checkTargetParentIdAvailable(targetParentId, fileIds)) {
            throw new RuntimeException("要复制的文件中包含选中的目标文件夹,请重新选择");
        }
        doCopyUserFiles(fileIds, targetParentId, userId);
    }

    /**
     * 保存复制文件
     *
     */
    private void doCopyUserFiles(String fileIds, Long targetParentId, Long userId) {
        // 查询所有要被复制的文件信息
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.in("\"id\"", fileIds);
        List<UserFile> toBeCopiedFileInfoList = userFileMapper.selectList(query);
        complementToBeCopiedFileInfoList(toBeCopiedFileInfoList, targetParentId, userId);
        // 批量新增文件信息
        for (UserFile userFile : toBeCopiedFileInfoList) {
            userFileMapper.insert(userFile);
        }
    }

    /**
     * 补全要复制的文件列表
     *
     */
    private void complementToBeCopiedFileInfoList(final List<UserFile> toBeCopiedFileInfoList,
                                                  final Long targetParentId, final Long userId) {
        final List<UserFile> allChildUserFileList = Lists.newArrayList();
        for (UserFile userFile : toBeCopiedFileInfoList) {
            Long fileId = userFile.getId();
            Long newFileId = IdGenerator.nextId();
            userFile.setParentId(targetParentId);
            userFile.setUserId(userId);
            userFile.setId(newFileId);
            userFile.setCreateUser(userId);
            userFile.setCreateTime(new Date());
            userFile.setUpdateUser(userId);
            userFile.setUpdateTime(new Date());
            // 处理名字重复的文件
            handleDuplicateFileName(userFile);
            if (isFolder(userFile)) {
                assembleAllChildUserFile(allChildUserFileList, fileId, newFileId, userId);
            }
        }
        toBeCopiedFileInfoList.addAll(allChildUserFileList);
    }

    /**
     * 查找并拼装子文件
     *
     */
    private void assembleAllChildUserFile(final List<UserFile> allChildUserFileList,
                                          Long parentUserFileId, Long newParentUserFileId, Long userId) {
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("parent_id", parentUserFileId);
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        List<UserFile> childUserFileList = userFileMapper.selectList(query);
        if (CollectionUtils.isEmpty(childUserFileList)) {
            return;
        }
        childUserFileList.forEach(childUserFile -> {
            Long fileId = childUserFile.getId(),
                    newFileId = IdGenerator.nextId();
            childUserFile.setParentId(newParentUserFileId);
            childUserFile.setUserId(userId);
            childUserFile.setId(newFileId);
            childUserFile.setCreateUser(userId);
            childUserFile.setCreateTime(new Date());
            childUserFile.setUpdateUser(userId);
            childUserFile.setUpdateTime(new Date());
            allChildUserFileList.add(childUserFile);
            if (isFolder(childUserFile)) {
                assembleAllChildUserFile(allChildUserFileList, fileId, newFileId, userId);
            }
        });
    }

    /**
     * 校验目标文件夹是否合法
     * 1、 不是选中的文件夹
     * 2、 不是选中文件夹的子文件夹
     *
     */
    private boolean checkTargetParentIdAvailable(Long targetParentId, String fileIds) {
        List<Long> fileIdList = StringListUtil.string2LongList(fileIds);
        if (fileIdList.contains(targetParentId)) {
            return false;
        }
        for (Long fileId : fileIdList) {
            // 判断选中的节点是targetParentId的子节点?
            if (checkIsChildFolder(targetParentId, userFileMapper.selectById(fileId))) {
                return false;
            }
        }
        return true;
    }


    /**
     * 检查目标文件是不是子文件夹(是否在目标文件夹下)
     *
     */
    private boolean checkIsChildFolder(Long targetParentId, UserFile userFile) {
        if (isFolder(userFile)) {
            List<UserFile> allChildrenFile = new ArrayList<>();
            findAllChildUserFile(allChildrenFile, userFile.getId());
            if (CollectionUtils.isNotEmpty(allChildrenFile)) {
                List<Long> childFolderIdList = allChildrenFile.stream()
                        .filter(this::isFolder).map(UserFile::getId).collect(Collectors.toList());
                return childFolderIdList.contains(targetParentId);
            }
        }
        return false;
    }

    /**
     * 查询文件的所有子节点
     */
    private void findAllChildUserFile(final List<UserFile> allChildUserFileList, Long parentId) {
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("parent_id", parentId);
        List<UserFile> childUserFileList = userFileMapper.selectList(query);
        if (CollectionUtils.isEmpty(childUserFileList)) {
            return;
        }
        allChildUserFileList.addAll(childUserFileList);
        for (UserFile userFile : childUserFileList) {
            if (isFolder(userFile)) {
                findAllChildUserFile(allChildUserFileList, userFile.getId());
            }
        }
    }

    /**
     * 校验是不是文件夹
     */
    private boolean isFolder(Long fileId, Long userId) {

        QueryWrapper<UserFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", fileId);
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        return isFolder(userFileMapper.selectOne(queryWrapper));
    }

    /**
     * 批量转移文件
     *
     */
    @Override
    public void transferFiles(String fileIds, Long targetParentId, Long userId) {
        if (!isFolder(targetParentId, userId)) {
            throw new RuntimeException("请选择要转移到的文件夹");
        }
        if (!checkTargetParentIdAvailable(targetParentId, fileIds)) {
            throw new RuntimeException("要转移的文件中包含选中的目标文件夹,请重新选择");
        }
        // 查询所有要被转移的文件信息
        QueryWrapper<UserFile> queryWrapper = new QueryWrapper<>();
        List<Long> idList = StringListUtil.string2LongList(fileIds);
        queryWrapper.in("\"id\"", idList);
        List<UserFile> toBeTransferredFileInfoList = userFileMapper.selectList(queryWrapper);

        // 转移文件
        toBeTransferredFileInfoList.forEach(userFile -> transferFile(userFile, targetParentId));
    }


    /**
     * 转移一个文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transferFile(UserFile userFile, Long targetParentId) {
        if (userFile.getParentId().equals(targetParentId)) {
            return;
        }
        userFile.setParentId(targetParentId);
        userFile.setUpdateUser(userFile.getCreateUser());
        userFile.setUpdateTime(new Date());
        handleDuplicateFileName(userFile);
        int cnt = userFileMapper.updateById(userFile);
        // 修改文件信息
        if (cnt != CommonConstant.ONE_INT) {
            log.error("文件转移失败,文件名称为:{}", userFile.getFilename());
            throw new RuntimeException("文件转移失败");
        }

    }


    /**
     * 秒传文件
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean secondUploadFile(Long parentId, String filename, String identifier, Long userId) {

        List<UploadFile> uploadFileList = uploadFileMapper
                .selectList(new QueryWrapper<UploadFile>().eq("identifier", identifier));
        if (CollectionUtils.isEmpty(uploadFileList)) {
            return false;
        }
        UploadFile uploadFile = uploadFileList.get(CommonConstant.ZERO_INT);
        addUserFile(parentId,
                filename,
                FileConstant.FolderFlagEnum.NO,
                FileTypeContext.getFileTypeCode(filename),
                uploadFile.getId(),
                userId,
                uploadFile.getFileSizeDesc());
        return true;
    }


    @Override
    public UserFile getById(Long fileId) {
        return userFileMapper.selectById(fileId);
    }

    @Override
    public UserFileParam getUserFileParam(Long fileId, Long userId) {
        UserFileVO userFileInfo = this.getUserFileInfo(fileId, userId);
        UserFileParam userFileParam = new UserFileParam();
        userFileParam.setRootFileId(userFileInfo.getFileId());
        userFileParam.setRootFilename(userFileInfo.getFilename());
        return userFileParam;

    }

    @Override
    public List<UserFileVO> getUserFileList(List<Long> fileIdList) {
       return userFileMapper.selectUserFileVOListByFileIdList(fileIdList);
    }


    /**
     * 获取对应文件列表的所有文件以及子文件信息
     *
     * @param fileIds
     * @return
     */
    @Override
    public List<UserFileVO> getAllUserFileVOList(String fileIds) {
        if (StringUtils.isBlank(fileIds)) {
            throw new RuntimeException(ResponseCode.ERROR_PARAM.getDesc());
        }
        List<UserFileVO> userFileVOList = userFileMapper
                .selectUserFileVOListByFileIdList(StringListUtil.string2LongList(fileIds));
        if (CollectionUtils.isEmpty(userFileVOList)) {
            return Lists.newArrayList();
        }
        final List<UserFileVO> allUserFileVOList = Lists.newArrayList(userFileVOList);
        userFileVOList.forEach(userFileVO -> findAllAvailableChildUserFile(allUserFileVOList, userFileVO));
        return allUserFileVOList;
    }

    /**
     * 递归查找所有子文件信息
     *
     * @param allUserFileVOList
     */
    private void findAllAvailableChildUserFile(List<UserFileVO> allUserFileVOList, UserFileVO userFileVO) {
        if (!isFolder(userFileVO)) {
            return;
        }
        // 获取没有逻辑删除的子节点
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("parent_id", userFileVO.getFileId());
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());

        List<UserFile> userFileList = userFileMapper.selectList(query);
        List<UserFileVO> userFileVOList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(userFileList)) {
            for (UserFile userFile : userFileList) {
                UserFileVO temp = new UserFileVO();
                BeanUtils.copyProperties(userFile, temp);
                temp.setFileId(userFile.getId());
                userFileVOList.add(temp);
            }
        }
        if (CollectionUtils.isEmpty(userFileVOList)) {
            return;
        }
        allUserFileVOList.addAll(userFileVOList);
        userFileVOList.forEach(userFileVOItem -> findAllAvailableChildUserFile(allUserFileVOList, userFileVOItem));
    }

    /**
     * 批量还原用户文件的删除状态
     */
    @Override
    public void restoreUserFiles(String fileIds, Long userId) {
        if (StringUtils.isBlank(fileIds) || Objects.isNull(userId)) {
            throw new RuntimeException("批量还原用户文件的删除状态失败");
        }
        List<Long> fileIdList = StringListUtil.string2LongList(fileIds);
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.in("\"id\"", fileIdList);
        List<UserFile> userFileList = userFileMapper.selectList(query);
        Set<String> cleanSet = userFileList.stream().map(rPanUserFile -> rPanUserFile.getParentId() + rPanUserFile.getFilename()).collect(Collectors.toSet());
        if (cleanSet.size() != userFileList.size()) {
            throw new RuntimeException("文件还原失败，该还原文件中存在同名文件，请逐个还原并重命名");
        }
        for (UserFile userFile : userFileList) {
            if (this.getDuplicateFileNameInDirCount(userFile.getUserId(),
                    userFile.getFilename(), userFile.getParentId()) != CommonConstant.ZERO_INT) {
                throw new RuntimeException("文件：" + userFile.getFilename() +
                        "还原失败，该文件夹中已有相同名称的文件或文件夹，请重命名后重试");
            }
        }
        // 还原用户文件
        UpdateWrapper<UserFile> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", userId);
        updateWrapper.in("\"id\"", fileIdList);
        updateWrapper.set("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        updateWrapper.set("update_user", userId);
        updateWrapper.set("update_time", new Date());
        if (userFileMapper.update(null, updateWrapper)!= fileIdList.size()) {
            throw new RuntimeException("批量还原用户文件的删除状态失败");
        }
    }

    /**
     * 同目录下重复名称的文件数量
     * @param userId
     * @param filename
     * @param parentId
     * @return
     */
    private long getDuplicateFileNameInDirCount( Long userId, String filename, Long parentId){

        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("user_id", userId);
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        query.eq("parent_id", parentId);
        query.eq("filename", filename);
        return  userFileMapper.selectCount(query);
    }

    @Override
    public List<UserFile> getBatchByFileId(List<Long> fileIdList) {
        return userFileMapper.selectBatchIds(fileIdList);
    }

    @Override
    public int deleteBatchUseFileByFileIdAndUserId(List<Long> fileIdList, Long userId) {
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("user_id", userId);
        query.in("\"id\"", fileIdList);
        return userFileMapper.delete(query);
    }

    /**
     * 校验是不是该物理文件还在使用
     * @param realFileId
     * @return
     */
    @Override
    public boolean checkRealFileUsed(Long realFileId) {
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("real_file_id", realFileId);
        long count = userFileMapper.selectCount(query);
        return count > CommonConstant.ZERO_INT;
    }

    /**
     * 获取面包屑列表
     *
     * @param fileId
     * @param userId
     * @return
     */
    @Override
    public List<BreadcrumbVO> getBreadcrumbs(Long fileId, Long userId) {
        // 根据用户id和del_flag 和folder_flag 获取用户文件信息
        QueryWrapper<UserFile> query = new QueryWrapper<>();
        query.eq("user_id", userId);
        query.eq("del_flag", FileConstant.DelFlagEnum.NO.getCode());
        query.eq("folder_flag", FileConstant.FolderFlagEnum.YES.getCode());
        List<UserFile> rPanUserFileList = userFileMapper.selectList(query);
        if (CollectionUtils.isEmpty(rPanUserFileList)) {
            return Lists.newArrayList();
        }
        Map<Long, BreadcrumbVO> breadcrumbVOTransferMap = rPanUserFileList.stream()
                .collect(Collectors.toMap(UserFile::getId, BreadcrumbVO::assembleBreadcrumbVO));
        List<BreadcrumbVO> breadcrumbVOList = Lists.newArrayList();
        BreadcrumbVO thisLevel = breadcrumbVOTransferMap.get(fileId);
        do {
            breadcrumbVOList.add(thisLevel);
            thisLevel = breadcrumbVOTransferMap.get(thisLevel.getParentId());
        } while (!Objects.isNull(thisLevel));
        Collections.reverse(breadcrumbVOList);
        return breadcrumbVOList;
    }

    @Override
    public void preview(Long fileId, HttpServletResponse response, Long userId) {
        if (isFolder(fileId, userId)) {
            throw new RuntimeException("不能预览文件夹");
        }
        UserFile userFile = userFileMapper.selectById(fileId);
        UploadFile uploadFile = uploadFileMapper.selectById(userFile.getRealFileId());
        preview(uploadFile.getRealPath(), response, uploadFile.getFilePreviewContentType());
    }

    /**
     * 文件预览
     */
    private void preview(String filePath, HttpServletResponse response, String filePreviewContentType) {
        this.addCommonResponseHeader(response, filePreviewContentType);
        try {
            uploadFileService.read2OutputStream(filePath, response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    /**
     * 添加公用的响应头
     *
     * @param response
     * @param contentTypeValue
     */
    private void addCommonResponseHeader(HttpServletResponse response, String contentTypeValue) {
        response.reset();
        HttpUtil.addCorsResponseHeader(response);
        response.setHeader(FileConstant.CONTENT_TYPE_STR, contentTypeValue);
        response.setContentType(contentTypeValue);
    }
}
